package com.yubest.springboothello;

import lombok.Getter;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.PostConstruct;
import javax.crypto.Cipher;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.*;

/**
 * @Author: hweiyu
 * @Description: TODO
 * @Date: 2024/11/14 11:34
 */
@Component
@Getter
public class SelfProtectionFilter extends OncePerRequestFilter {

    private String licMac;

    private long licLastTime;

    @PostConstruct
    public void init() {
        Map<String, Object> licMap = getLic();
        this.licMac = licMap.get("mac").toString();
        this.licLastTime = Long.valueOf(licMap.get("lastTime").toString());

        this.check();
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        System.out.println("*******************************************");
        this.check();
    }

    private void check() {
        long now = System.currentTimeMillis();
        if (now < getLicLastTime()) {
            System.out.println("Time Error!");
            System.exit(0);
        }
        List<String> sysMacList = getSysMacList();
        if (!sysMacList.contains(getLicMac())) {
            System.out.println("Sys Error!");
            System.exit(0);
        }
    }

    private List<String> getSysMacList() {
        List<String> sysMacList = new ArrayList<>();
        String mac = null;
        try {
            for (Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces();
                 networkInterfaces.hasMoreElements();) {
                NetworkInterface networkInterface = (NetworkInterface) networkInterfaces.nextElement();
                for (Enumeration inetAddresses = networkInterface.getInetAddresses();
                     inetAddresses.hasMoreElements();) {
                    InetAddress inetAddr = (InetAddress) inetAddresses.nextElement();
                    if (!inetAddr.isLoopbackAddress()
                            && !inetAddr.isLinkLocalAddress()
                            && !inetAddr.isMulticastAddress()) {
                        mac = getMacByInetAddress(inetAddr);
                        if (null != mac) {
                            sysMacList.add(mac);
                        }
                    }
                }
            }
        } catch (Exception e) {
            ;//ignore
        }
        return sysMacList;
    }

    private String getMacByInetAddress(InetAddress inetAddr) {
        try {
            byte[] mac = NetworkInterface.getByInetAddress(inetAddr).getHardwareAddress();
            StringBuilder buf = new StringBuilder();
            for (int i = 0; i < mac.length; i++) {
                if (i != 0) {
                    buf.append("-");
                }
                String temp = Integer.toHexString(mac[i] & 0xff);
                if (temp.length() == 1) {
                    buf.append("0").append(temp);
                } else {
                    buf.append(temp);
                }
            }
            return buf.toString().toUpperCase();
        } catch (SocketException e) {
            e.printStackTrace();
        }
        return null;
    }

    private Map<String, Object> getLic() {
        Map<String, Object> map = new HashMap<>();
        try(InputStream is = SelfProtectionFilter.class.getClassLoader().getResourceAsStream("lic");
            ByteArrayOutputStream os = new ByteArrayOutputStream()) {
            StreamUtils.copy(is, os);
            String context = decrypt(os.toByteArray());
            String[] arr = context.split(";");
            for (String str : arr) {
                String[] kv = str.split("=");
                map.put(kv[0], kv[1]);
            }
        } catch (IOException e) {
            ;//ignore
        }
        return map;
    }

    private String decrypt(byte[] data) {
        try {
            String key = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALhrQ8XpZtPehe9B4F+B6G5QkAKigXX6sh8zorr+btteTshzQ/2NrexODxYxEDt/7e+Q+sdKTJbguxpN2ESiN3tEAAHCNVK/Sqctk1xqVSjZKQLejmeeK4EvzYD8RfhzrnlSEsH6xw83ptfJwQjRQk2aD/TOHtBHL6QSbMIUgi/lAgMBAAECgYB7a64LwcyDdqUEHn5e7L31Ng1q9f7WSlTy9MevhaADR/ZJyHp0MmF3iDYoj+VhLJi8f7aVsW/YecY+MGLQbA/cVm4CvbdvdXrlQERbm6ZwTvaqlk3nX1CmqKySsQaI/n4whAbvbQQ4z5mxvv5nqj6IbeEiyvAJ8f47OvmYRJoW8QJBAPJvHngGpqdQN0cqjRnJINF0+65E1aoumPTOwNGF5ZvtaC97uH+7lHbgu2IHvc2SAELsulHNv3jYS/IePGd00z8CQQDCvROwkdH1CZLJDYYTM9ObnM/lsNj3szBpY97J+EIRWyPAyuTZdlP/fh/PUEk2gJarwusJCTLJk85NPrKDRUfbAkEAz85P37JTx7cKqwXeTOwKJYCQ+6AlResLUUyoGvEbD71AQPNcAqFXcU7RUAYyu7MaZkNkshoatgsxjig8vrF1IQJAZ4J++8SWmCuthQaWNJDAsp8odkuJGCh73BkEq9A0ter+1xRBjkFyJoTQva5MLBcvfz7NFXF5OGJDLxXbZyElLwJAJ9LZ3m3D9GUMeNNSiXN5ZL0JBIqER1UW/7zq0WD/HwcG34Q04q4RdwHbDGSpsBoKgMYtdu4UMNaVhzOd4NZ9Bw==";
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(key));
            PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec);
            Cipher cipher = Cipher.getInstance("RSA");
            //根据密钥，对Cipher对象进行初始化
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] res = cipher.doFinal(data);
            assert res != null;
            return new String(res, StandardCharsets.UTF_8);
        } catch (Exception e) {
            ;//ignore
        }
        return null;
    }
}
